<template>
  <layout-content :header="$t('business.dashboard.dashboard')">
    <el-row :gutter="24" class="row-box">
      <el-col :span="24">
        <el-card
          v-if="cluster"
          class="el-card"
          shadow="always"
          style="background-color: #243441; height: 120px"
        >
          <el-row :gutter="24">
            <el-col :span="8">
              <span class="title">{{ $t("commons.table.name") }}</span>
              <div style="text-align: center">
                <el-tooltip
                  class="item"
                  effect="dark"
                  :content="cluster.name"
                  placement="top"
                >
                  <h1>{{ cluster.name | max15letter }}</h1>
                </el-tooltip>
              </div>
            </el-col>
            <el-col :span="8">
              <span class="title">{{ $t("business.cluster.version") }}</span>
              <div class="line"></div>
              <div style="text-align: center">
                <el-tooltip
                  class="item"
                  effect="dark"
                  :content="cluster.status.version"
                  placement="top"
                >
                  <h1>{{ cluster.status.version | max15letter }}</h1>
                </el-tooltip>
              </div>
            </el-col>
            <el-col :span="8">
              <span class="title">{{ $t("commons.table.created_time") }}</span>
              <div class="line"></div>
              <div style="text-align: center">
                <el-tooltip
                  class="item"
                  effect="dark"
                  :content="cluster.createAt | age"
                  placement="top"
                >
                  <h1>{{ cluster.createAt | age }}</h1>
                </el-tooltip>
              </div>
            </el-col>
          </el-row>
        </el-card>
      </el-col>
    </el-row>
    <br />

    <el-row :gutter="20" v-if="showMetric && hasMetric === 'true'">
      <el-col :span="12">
        <el-card style="background-color: #212e38" class="n-card el-card">
          <span
            >CPU(core) {{ clusterInfo.metricCpu }} /
            {{ clusterInfo.allocatCpu }}</span
          >
          <el-progress
            style="margin-top: 20px"
            :stroke-width="20"
            :percentage="clusterInfo.cpuPercent"
          ></el-progress>
        </el-card>
      </el-col>
      <el-col :span="12">
        <el-card style="background-color: #212e38" class="n-card el-card">
          <span
            >Memory(Gi) {{ clusterInfo.metricMemory }} /
            {{ clusterInfo.allocatMemory }}</span
          >
          <el-progress
            style="margin-top: 20px"
            :stroke-width="20"
            :percentage="clusterInfo.memoryPercent"
          ></el-progress>
        </el-card>
      </el-col>
    </el-row>
    <el-row v-if="showMetric && hasMetric !== 'true'">
      <el-alert type="info" :closable="false">
        <el-button
          type="text"
          style="font-size: 15px"
          @click="dialogMetricVisible = true"
          icon="el-icon-warning"
          >{{ $t("business.dashboard.metric_server_help") }}</el-button
        >
      </el-alert>
    </el-row>
    <br />

    <el-row :gutter="20" class="resources row-box">
      <el-col
        v-for="(resource, index) in resources"
        v-bind:key="resource.name"
        :xs="8"
        :sm="8"
        :lg="6"
      >
        <el-card
          :body-style="{ padding: '0px' }"
          @click.native="jumpTo(resource.name)"
          class="d-card el-card"
        >
          <el-row :gutter="24">
            <el-col :span="10">
              <div>
                <ko-charts
                  :chart-data="resource"
                  :key="resource.name"
                  :index="index"
                ></ko-charts>
              </div>
            </el-col>
            <el-col :span="14">
              <div class="card-content">
                <span>{{ resource.name }}</span>
                <h1 style="text-align: right">
                  <a>{{ resource.count }}</a>
                </h1>
              </div>
            </el-col>
          </el-row>
        </el-card>
      </el-col>
    </el-row>
    <el-row
      :gutter="24"
      v-has-permissions="{ apiGroup: '', resource: 'events', verb: 'list' }"
    >
      <h4 style="margin-left: 10px; float: left">
        {{ $t("business.event.event") }}
      </h4>
      <complex-table
        style="margin-top: 20px"
        :data="events"
        @search="search"
        v-loading="loading"
        :pagination-config="paginationConfig"
        :search-config="searchConfig"
      >
        <el-table-column
          :label="$t('business.event.reason')"
          prop="reason"
          fix
          max-width="50px"
        >
          <template #default="{ row }">
            {{ row.reason }}
          </template>
        </el-table-column>
        <el-table-column
          :label="$t('business.namespace.namespace')"
          prop="namespace"
          fix
          max-width="50px"
        >
          <template #default="{ row }">
            {{ row.metadata.namespace }}
          </template>
        </el-table-column>
        <el-table-column
          :label="$t('business.event.message')"
          prop="resource"
          fix
          min-width="200px"
          show-overflow-tooltip
        >
          <template #default="{ row }">
            {{ row.message }}
          </template>
        </el-table-column>
        <el-table-column
          :label="$t('business.event.resource')"
          prop="resource"
          fix
          min-width="200px"
          show-overflow-tooltip
        >
          <template #default="{ row }">
            <span
              class="span-link"
              @click="
                toResource(
                  row.involvedObject.kind,
                  row.metadata.namespace,
                  row.involvedObject.name
                )
              "
            >
              {{ row.involvedObject.kind }} / {{ row.involvedObject.name }}
            </span>
          </template>
        </el-table-column>
        <el-table-column
          :label="$t('commons.table.time')"
          prop="metadata.creationTimestamp"
          fix
        >
          <template #default="{ row }">
            <span v-if="row.eventTime">{{ row.eventTime | age }}</span>
            <span v-else-if="row.lastTimestamp">{{
              row.lastTimestamp | age
            }}</span>
            <span v-else-if="row.firstTimestamp">{{
              row.firstTimestamp | age
            }}</span>
          </template>
        </el-table-column>
      </complex-table>
    </el-row>
    <div v-if="dialogMetricVisible">
      <metric-server
        @changeVisble="changeVisble"
        :clusterName="clusterName"
        :visible="dialogMetricVisible"
      />
    </div>
  </layout-content>
</template>

<script>
import LayoutContent from "@/views/domain/kubeHud/views/components/layout/LayoutContent.vue";
import KoCharts from "@/components/ko-charts";
import { listNamespace } from "@/api/namespaces";
import { listDeployments } from "@/api/deployments";
import { listStatefulSets } from "@/api/statefulsets";
import { listDaemonSets } from "@/api/daemonsets";
import { listServices } from "@/api/services";
import { listNodes } from "@/api/nodes";
import ComplexTable from "@/views/domain/kubeHud/views/components/complex-table/index.vue";
import { listEvents } from "@/api/events";
import { getCluster } from "@/api/clusters";
import { checkPermissions } from "@/utils/permission";
import { mixin } from "@/utils/resourceRoutes";
import { listConfigMaps } from "@/api/configmaps";
import { listSecrets } from "@/api/secrets";
import { listNodeMetrics } from "@/api/apis";
import { cpuUnitConvert, memoryUnitConvert } from "@/utils/unitConvert";
import MetricServer from "@/components/ko-plugin/metric-server";

export default {
  name: "Dashboard",
  components: { ComplexTable, KoCharts, MetricServer, LayoutContent },
  mixins: [mixin],
  data() {
    return {
      cluster: null,
      clusterName: "",
      resources: [],
      events: [],
      paginationConfig: {
        currentPage: 1,
        pageSize: 10,
        total: 0
      },
      searchConfig: {
        keywords: ""
      },
      showMetric: true,
      hasMetric: "false",
      clusterInfo: {
        allocatCpu: 0,
        allocatMemory: 0,
        cpuPercent: 0,
        metricCpu: 0,
        metricMemory: 0,
        metricPercent: 0
      },
      dialogMetricVisible: false,
      loading: false
    };
  },
  methods: {
    formatCpu(percentage) {
      return `${percentage}% \nCPU`;
    },
    formatMemory(percentage) {
      return `${percentage}% \nMemory`;
    },
    changeVisble(val) {
      this.dialogMetricVisible = val;
    },
    jumpTo(val) {
      this.$router.push({ name: val });
    },
    listResources() {
      getCluster(this.clusterName).then(res => {
        this.cluster = res.data;
      });
      if (
        checkPermissions({
          scope: "cluster",
          apiGroup: "",
          resource: "nodes",
          verb: "list"
        })
      ) {
        listNodes(this.clusterName).then(res => {
          const nodes = {
            name: "Nodes",
            count: res.items ? res.items.length : 0,
            data: [
              {
                value: res.items ? res.items.length : 0
              }
            ]
          };
          this.clusterInfo.allocatCpu = 0;
          this.clusterInfo.allocatMemory = 0;
          for (const n of res.items) {
            if (n.status?.allocatable?.cpu) {
              this.clusterInfo.allocatCpu += cpuUnitConvert(
                n.status.allocatable.cpu
              );
            }
            if (n.status?.allocatable?.memory) {
              this.clusterInfo.allocatMemory += memoryUnitConvert(
                n.status.allocatable.memory
              );
            }
          }
          this.resources.push(nodes);
          listNodeMetrics(this.clusterName)
            .then(metricNodes => {
              this.hasMetric = "true";
              this.clusterInfo.metricCpu = 0;
              this.clusterInfo.metricMemory = 0;
              for (const n of metricNodes.items) {
                if (n.usage?.cpu) {
                  this.clusterInfo.metricCpu += cpuUnitConvert(n.usage.cpu);
                }
                if (n.usage?.memory) {
                  this.clusterInfo.metricMemory += memoryUnitConvert(
                    n.usage.memory
                  );
                }
              }
              this.clusterInfo.allocatCpu = Number(
                (this.clusterInfo.allocatCpu / 1000).toFixed(2)
              );
              this.clusterInfo.allocatMemory = Number(
                (this.clusterInfo.allocatMemory / 1024).toFixed(2)
              );
              this.clusterInfo.metricCpu = Number(
                (this.clusterInfo.metricCpu / 1000).toFixed(2)
              );
              this.clusterInfo.metricMemory = Number(
                (this.clusterInfo.metricMemory / 1024).toFixed(2)
              );
              this.clusterInfo.cpuPercent = Math.round(
                (
                  this.clusterInfo.metricCpu / this.clusterInfo.allocatCpu
                ).toFixed(2) * 100
              );
              this.clusterInfo.memoryPercent = Math.round(
                (
                  this.clusterInfo.metricMemory / this.clusterInfo.allocatMemory
                ).toFixed(2) * 100
              );
            })
            .catch(() => {
              this.hasMetric = "false";
            });
        });
      }
      if (
        checkPermissions({
          scope: "cluster",
          apiGroup: "",
          resource: "namespaces",
          verb: "list"
        })
      ) {
        listNamespace(this.clusterName).then(res => {
          const namespaces = {
            name: "Namespaces",
            count: res.items ? res.items.length : 0,
            data: [
              {
                value: res.items ? res.items.length : 0
              }
            ]
          };
          this.resources.push(namespaces);
        });
      }
      if (
        checkPermissions({
          scope: "namespace",
          apiGroup: "apps",
          resource: "deployments",
          verb: "list"
        })
      ) {
        listDeployments(this.clusterName).then(res => {
          const deployments = {
            name: "Deployments",
            count: res.items ? res.items.length : 0,
            data: [
              {
                value: res.items ? res.items.length : 0
              }
            ]
          };
          this.resources.push(deployments);
        });
      }
      if (
        checkPermissions({
          scope: "namespace",
          apiGroup: "apps",
          resource: "statefulsets",
          verb: "list"
        })
      ) {
        listStatefulSets(this.clusterName).then(res => {
          const statefulSets = {
            name: "StatefulSets",
            count: res.items ? res.items.length : 0,
            data: [
              {
                value: res.items ? res.items.length : 0
              }
            ]
          };
          this.resources.push(statefulSets);
        });
      }
      if (
        checkPermissions({
          scope: "namespace",
          apiGroup: "apps",
          resource: "daemonsets",
          verb: "list"
        })
      ) {
        listDaemonSets(this.clusterName).then(res => {
          const daemonSets = {
            name: "DaemonSets",
            count: res.items ? res.items.length : 0,
            data: [
              {
                value: res.items ? res.items.length : 0
              }
            ]
          };
          this.resources.push(daemonSets);
        });
      }
      if (
        checkPermissions({
          scope: "namespace",
          apiGroup: "",
          resource: "services",
          verb: "list"
        })
      ) {
        listServices(this.clusterName).then(res => {
          const services = {
            name: "Services",
            count: res.items ? res.items.length : 0,
            data: [
              {
                value: res.items ? res.items.length : 0
              }
            ]
          };
          this.resources.push(services);
        });
      }
      if (
        checkPermissions({
          scope: "namespace",
          apiGroup: "",
          resource: "configmaps",
          verb: "list"
        })
      ) {
        listConfigMaps(this.clusterName).then(res => {
          const services = {
            name: "ConfigMaps",
            count: res.items ? res.items.length : 0,
            data: [
              {
                value: res.items ? res.items.length : 0
              }
            ]
          };
          this.resources.push(services);
        });
      }
      if (
        checkPermissions({
          scope: "namespace",
          apiGroup: "",
          resource: "secrets",
          verb: "list"
        })
      ) {
        listSecrets(this.clusterName).then(res => {
          const services = {
            name: "Secrets",
            count: res.items ? res.items.length : 0,
            data: [
              {
                value: res.items ? res.items.length : 0
              }
            ]
          };
          this.resources.push(services);
        });
      }
      this.search();
    },
    search(resetPage) {
      this.loading = true;
      if (resetPage) {
        this.paginationConfig.currentPage = 1;
      }
      if (
        checkPermissions({
          scope: "namespace",
          apiGroup: "",
          resource: "events",
          verb: "list"
        })
      ) {
        listEvents(
          this.clusterName,
          true,
          this.searchConfig.keywords,
          this.paginationConfig.currentPage,
          this.paginationConfig.pageSize
        ).then(res => {
          this.loading = false;
          this.events = res.items;
          this.paginationConfig.total = res.total;
        });
      }
    },
    getData(items, keys) {
      let key = [];
      let result = [];
      for (const item of items) {
        const name = this.traverse(item, keys);
        if (key.indexOf(name) === -1) {
          key.push(name);
          const d = {
            value: 1,
            name: name
          };
          result.push(d);
        } else {
          for (let i = 0; i < result.length; i++) {
            if (result[i].name === name) {
              result[i].value++;
              break;
            }
          }
        }
      }
      if (items.length === 0) {
        result = [
          {
            value: 0
          }
        ];
      }
      return result;
    },
    traverse(obj, keys) {
      if (keys === "status.conditions.type") {
        if (
          obj.status.conditions[0].type &&
          obj.status.conditions[0].status === "True"
        ) {
          return obj.status.conditions[0].type;
        } else {
          return "Error";
        }
      } else if (keys === "status.replicas") {
        return "In Progress";
      } else if (
        keys === "metadata.status.active" ||
        keys === "status.loadBalancer"
      ) {
        return "Active";
      } else if (keys === "status.numberUnavailable") {
        if (obj.status.numberUnavailable > 0) {
          return "Error";
        } else {
          return "Active";
        }
      } else {
        return keys.split(".").reduce(function (cur, key) {
          return cur[key];
        }, obj);
      }
    }
  },
  created() {
    this.clusterName = this.$route.query.cluster;
    this.showMetric =
      checkPermissions({
        scope: "cluster",
        apiGroup: "",
        resource: "nodes",
        verb: "list"
      }) &&
      checkPermissions({
        scope: "cluster",
        apiGroup: "metrics.k8s.io",
        resource: "nodes",
        verb: "list"
      });
    this.listResources();
  }
};
</script>

<style scoped>
.line {
  float: left;
  margin-top: 10px;
  width: 1px;
  height: 80px;
  background: #3884c5;
}

.title {
  margin-left: 10px;
  color: #a1a9ae;
}

.d-card {
  height: 90px;
  background-color: #1d3e4d;
  margin-top: 10px;
}

.n-card {
  height: 100px;
  background-color: #1d3e4d;
  margin-top: 10px;
  border: none;
}

.card-content {
  margin-top: 10px;
  margin-right: 10px;
  text-align: center;
  float: right;
}

.card-content > span:first-child {
  color: #a1a9ae;
}
</style>
